/***********************************************************************************
Copy right:	    Coffee Tech.
Author:         jiaoyue
Date:           2021-11-21
Description:    设备采集服务
***********************************************************************************/

#include "edge_pub.h"
#include "ec_service.h"
#include <unix_sock.h>
#include <log_utils.h>
#include <nv_utils.h>
#include <shmem.h>
#include <modbus/modbus.h>

#define MODULE EC_NAME

/****************************************************************/
//modbus需要的
#define MB_START_0      1
#define MB_END_0        9999

#define MB_START_1      10001
#define MB_END_1        19999

#define MB_START_3      30001
#define MB_END_3        39999

#define MB_START_4      40001
#define MB_END_4        49999
/****************************************************************/
static struct unix_param ec_unix_ser;
static struct shm_param para;
static struct node_cache data_nodes;      //数据点cache
static struct mb_node_list mb_list;       //modbus数据点配置链表
//static char ec_unix_buf[MAX_UNIX_LEN];    //用于接收unix,控制json的缓冲区
static modbus_t *mb;                      //modbus连接描述符
/****************************************************************/

static int shm_get(void)
{
    int ret = -1;

    ret = shm_init(&para, EDGE_SHM_NAME, MAX_NODE_SIZE);
    if (ret < 0)
    {
        return -1;
    }

    void *node_p = shm_getaddr(&para);
    if (node_p == NULL)
    {
        return -1;
    }

    data_nodes.total = (int *)node_p;
    data_nodes.node_p = (struct std_node *)(node_p + sizeof(int));

    for (int i = 0; i < *data_nodes.total; i++)
    {
        LOGD("node %d - key %d", i, data_nodes.node_p[i].key);
    }

    return 0;
}

/**
 * @brief 从共享内存中获取响应的节点空间
 * @param key 节点的key值
 * @return 成功返回节点空间地址，失败返回NULL
 */
static struct std_node *get_mem_node(int key)
{
    for (int i = 0; i < *data_nodes.total; i++)
    {
        if(data_nodes.node_p[i].key == key)
        {
            return &data_nodes.node_p[i];
        }
    }

    return NULL;
}

/**
 * @brief 解析modbus点表
 * @return
 */
static int mb_nodes_init(void)
{
    //解析m0的数据点
    int arr_size = -1;

    struct nv_obj *pobj;

    //解析点表
    struct list_head nv_list;

    nv_get_list_from_file(&nv_list, NODE_CONFIG_PAHT);

    pobj = nv_get_list_obj(&nv_list, "modbus.data.arr_size");
    if (NULL == pobj)
    {
        LOG_STD(APP_ERR, "get err");
        return -1;
    }
    arr_size = pobj->valueint;
    LOG_STD(APP_DEBUG, "modbus arr size = %d", arr_size);

    struct mb_node_list *nodep; //当前节点

    INIT_LIST_HEAD(&mb_list.list);
    for (int i = 0; i < arr_size; i++)
    {
        char key_str[256] = {0};
        char type_str[256] = {0};
        char name_str[256] = {0};
        char addr_str[256] = {0};

        snprintf(key_str, 255, "modbus.data[%d].key", i);
        snprintf(type_str, 255, "modbus.data[%d].type", i);
        snprintf(name_str, 255, "modbus.data[%d].name", i);
        snprintf(addr_str, 255, "modbus.data[%d].addr", i);

        //申请节点内存
        nodep = (struct mb_node_list *)malloc(sizeof(*nodep));
        bzero(nodep, sizeof(*nodep));

        pobj = nv_get_list_obj(&nv_list, key_str);
        nodep->node.key = pobj->valueint;

        pobj = nv_get_list_obj(&nv_list, type_str);
        nodep->node.type = pobj->valueint;

        pobj = nv_get_list_obj(&nv_list, name_str);
        strcpy(nodep->node.name, pobj->valuestring);

        pobj = nv_get_list_obj(&nv_list, addr_str);
        nodep->node.addr = pobj->valueint;

        list_add_tail(&nodep->list, &mb_list.list);

        LOGD("mb node %s, key %d", nodep->node.name, nodep->node.key);
    }

    nv_list_free(&nv_list);

    return 0;
}


int modbus_init()
{
    //先解析出modbus设备的地址和端口
    char addr[64] = {0};
    int port;

    struct list_head nv_list;
    nv_get_list_from_file(&nv_list, NODE_CONFIG_PAHT);

    struct nv_obj *pobj;
    pobj = nv_get_list_obj(&nv_list, "mb_dev.addr");
    if(NULL == pobj)
    {
        LOG_STD(APP_ERR, "err get mqtt addr");
        exit(-1);
    }
    strcpy(addr, pobj->valuestring);

    pobj = nv_get_list_obj(&nv_list, "mb_dev.port");
    if(NULL == pobj)
    {
        LOG_STD(APP_ERR, "err get mqtt port");
        exit(-1);
    }
    port = pobj->valueint;

    LOG_STD(APP_NOTICE, "modbus dev addr=%s, port=%d",\
            addr, port);

    //nv_get_list和nv_list_free成对存在
    nv_list_free(&nv_list);

    mb = modbus_new_tcp(addr, port);
    if(NULL == mb)
    {
        LOGE("modbus_new_tcp err");
        return -1;
    }
    modbus_set_slave(mb, 1);
    int ret = modbus_connect(mb);
    if(ret < 0)
    {
        LOGE("connect err");
        return -1;
    }

    LOGN("connect success");

    return 0;
}

/**
 * @brief 初始化服务
 * @return 0 -1
 */
int init_ec_service()
{
    //初始化unix_sock的服务端
    if(unix_init_server(&ec_unix_ser, EC_NAME) < 0)
    {
        LOGE("error to unix_init_server");
        return -1;
    }

    //获取映射的共享内存
    if(shm_get() < 0)
    {
        LOGE("can not get shm %s", para.name);
        return -1;
    }

    //解析点表
    if(mb_nodes_init() < 0)
    {
        LOGE("parse node err");
        return -1;
    }

    return 0;
}

/**
 * @brief 采集modbus的数据，并转化到共享内存中
 * @param arg
 * @return
 */
void *mb_collect_thread(void *arg)
{
    int ret;
    struct list_head *pos;
    struct mb_node_list *tmp;
    uint16_t buf[8] = {0};
    uint8_t bit_buf[8];

    while (1)
    {
        list_for_each(pos, &mb_list.list)
        {
            tmp = list_entry(pos, struct mb_node_list, list);

            //获取共享内存中的映射节点
            struct std_node *mem_node = get_mem_node(tmp->node.key);
            if(NULL == mem_node)
            {
                LOGW("get_mem_node key = %d err\n", tmp->node.key);
                continue;
            }

            //需要将PLC的地址转换为modbus的地址
            int addr = tmp->node.addr % 10000 - 1;
            //判断
            switch (tmp->node.type) {
            case NODE_TYPE_BOOL:
                //读一个位并转换到buf中，已经转换完毕，不需要移位
                ret = modbus_read_bits(mb, addr, 1, bit_buf);
                if(ret < 0)
                {
                    LOGW("read err\n");
                    break;
                }
                mem_node->new_val.b_val = bit_buf[0];
                //LOGD("read addr %d, val=%d", tmp->node.addr, mem_node->new_val.b_val)

                break;
            case NODE_TYPE_INT:

                break;
            case NODE_TYPE_FLOAT:
                //判断是输入寄存器还是保存寄存器
                if(tmp->node.addr >= MB_START_4 && tmp->node.addr <= MB_END_4)
                {
                    ret = modbus_read_registers(mb, addr, 1, buf);
                    if(ret < 0)
                    {
                        LOGW("read err\n");
                        break;
                    }
                    float val = modbus_get_float_dcba(buf);
                    //将转换后的数据写到共享内存中
                    mem_node->new_val.f_val = val;
                }
                else if (tmp->node.addr >= MB_START_3 && tmp->node.addr <= MB_END_3)
                {
                    ret = modbus_read_input_registers(mb, addr, 1, buf);
                    if(ret < 0)
                    {
                        LOGW("read err\n");
                        break;
                    }
                    float val = modbus_get_float_dcba(buf);
                    //将转换后的数据写到共享内存中
                    mem_node->new_val.f_val = val;
                }

                //LOGD("read addr %d, val=%.2f", tmp->node.addr, mem_node->new_val.f_val)
                break;
            default:
                break;
            }
        }
        sleep(2);
    }
}


/**
 * @brief 接收来自上层进程的指令，解析并处理
 * @param arg
 * @return
 */
void *msg_handle_thread(void *arg)
{
    while (1)
    {
        sleep(1);
    }
}

